// Name: map.js
// Description: Construct a google map centered
// in Portland, OR in the #map container of an html
// document.
// Written by:  Tanya L. Crenshaw
// Modified by: Ailes, Alraddadi, Jorgensen, Mercer

	
var ENABLE_MARKERS = false; //display a marker at center of each zip
var MIN_COLOR_PCT = 20; //the minimum darkness percentage for coloring zips
var DARK_HIGH = true; //whether dark shading represents high values (such as SAT) for zips

//The google map	
var map;
	
var currentMetric = 'applied';
	
//value ranges for coloring
var minSat = 1600;
var maxSat = 0;

var minGpa = 4.0;
var maxGpa = 0.0;

var minApplied = Number.MAX_VALUE;
var maxApplied = 0;

var minEnrolled = Number.MAX_VALUE;
var maxEnrolled = 0;
	

// Initialize map information
function mapSetup(){
	
	var myOptions = {
      zoom: 7,
	  // The center point of the map is San Diego, CA
      center: new google.maps.LatLng(45.540022,-122.671967),
      mapTypeId: google.maps.MapTypeId.ROADMAP
    };


	map = new google.maps.Map(document.getElementById("map"),
        myOptions);
		
	//Add helper functions to zipCodes array and calc min and max values
	for (var key in zipCodes) {
		zipCodes[key].constructZipCodeArray = function(){
				var zipCoords = [];
				for (var i = 0; i < this.coords.length; i++) {
					zipCoords[i] = new google.maps.LatLng(this.coords[i][1], this.coords[i][0]);
				}
				return zipCoords;
			};
		
		zipCodes[key].constructZipCodeCenter = function(){
				return new google.maps.LatLng(this.center[1], this.center[0]);
			};
		
		zipCodes[key].getAvgSat = function(){
				var sum = 0;
				for (var i = 0; i < this.sat.length; i++) {
					sum += this.sat[i][0] + this.sat[i][1];
				}
				return sum / this.sat.length;
			};
			
		zipCodes[key].getAvgGpa = function(){
				var sum = 0;
				for(var i=0; i < this.gpa.length; i++) {
					sum += this.gpa[i][0];
				}
				return sum / this.gpa.length;
			};
		
		//Display a marker for each zip if enabled
		if (ENABLE_MARKERS) {
			var marker = new google.maps.Marker({
				position: zipCodes[key].constructZipCodeCenter(),
				map: map,
				title: key
			});
		}
		
		var satAvg = zipCodes[key].getAvgSat();
		if(satAvg > maxSat) maxSat = satAvg;
		if(satAvg < minSat) minSat = satAvg;
		
		var gpaAvg = zipCodes[key].getAvgGpa();
		if(gpaAvg > 4.0) alert('Invalid gpa at zip : '+key);
		if(gpaAvg > maxGpa) maxGpa = gpaAvg;
		if(gpaAvg < minGpa) minGpa = gpaAvg;
		
		var applied = zipCodes[key].applied;
		if(applied > maxApplied) maxApplied = applied;
		if(applied < minApplied) minApplied = applied;
		
		var enrolled = zipCodes[key].enrolled;
		if(enrolled > maxEnrolled) maxEnrolled = enrolled;
		if(enrolled < minEnrolled) minEnrolled = enrolled;
		
	}
	
	//Create polygons for each zip code and shade them
	for (var key in zipCodes) {
		
		// Create the polygon that outlines zipcode 97303
		// Call the function constructZipCodeArray() to 
		// get the path of geopgraphical points.
		var zipCodeArea = new google.maps.Polygon({
			paths: zipCodes[key].constructZipCodeArray(),
			strokeColor: "#333y",
			strokeOpacity: 0.8,
			strokeWeight: 0.5,
			fillColor: "rgb(0, 0, 0)", //getFillShading(zipCodes[key].applied, minApplied, maxApplied),
			fillOpacity: 0.7,
			title: key,
			avgSat : zipCodes[key].getAvgSat()
		});		
		
		zipCodeArea.setMap(map);
		
		zipCodes[key].poly = zipCodeArea; //assign zip polygon
		
				
		//Attach a zip code sat score message to each zip
		attachMsg(zipCodeArea, "Zip Code: "+key
			+"\r\nNumber applied: "+zipCodes[key].applied
			+"\r\nNumber enrolled: "+zipCodes[key].enrolled
			+"\r\nAverage GPA: "+Math.round(zipCodes[key].getAvgGpa()*100)/100
			+"\r\nAverage SAT: "+Math.round(zipCodes[key].getAvgSat())
			);
	}
	
	recolor(); //Color the zips
	
	/**
	 * 
	 * Attach the specified message to the specified polygon so
	 * 	that message appears when the polygon is clicked.
	 *
	 * @param {Object} poly
	 * @param {Object} message
	 */
	function attachMsg(poly, message){
		google.maps.event.addListener(poly, "click", function(){
			alert(message);
		});
	}
	
	map.keyboardShortcuts = false;
	
	//Add events listeners when zooming or dragging the map.
	google.maps.event.addListener(map, 'dragend', mapUpdated);
	google.maps.event.addListener(map, 'zoom_changed', mapUpdated);
}

/**
 * Event handler for map updated bounds or zoom or click
 */
function mapUpdated(){
	var dynamicRecoloringBox = document.getElementById('dynamicRecoloringBox');
	if(dynamicRecoloringBox.checked){
		dynamicRecolor('applied');
	}
}

/**
 * Event handler for dynamic recoloring button
 */
function dynamicRecoloring(){
	var dynamicRecoloringBox = document.getElementById('dynamicRecoloringBox');
	if(dynamicRecoloringBox.checked){
		dynamicRecolor();
	}else{
		recolor();
	}
}

/**
 * Event handler for metric radio buttons
 * 
 * @param {Object} metric - {sat, gpa, enrolled, applied}
 * 		the metric changing to
 */
function metricClicked(metric){
	if(currentMetric != metric){
		currentMetric = metric;
		
		var dynamicRecoloringBox = document.getElementById('dynamicRecoloringBox');
		if(dynamicRecoloringBox.checked){
			dynamicRecolor();
		}else{
			recolor();
		}	
	}
}

/**
 * Set current display metric
 * @param {Object} metric - {'sat', 'gpa', 'enrolled', 'applied'} 
 */
function setMetric(metric){
	currentMetric = metric;
}

/**
 * Recolor dynamically according to metric specified
 */
function dynamicRecolor(){
	
	//local versions of overall values which apply for zips
	// within current window only
	var minSatl=1600, maxSatl=0, minGpal=4.00, maxGpal=0.0, 
		minEnrolledl = minAppliedl = Number.MAX_VALUE, 
		maxEnrolledl = maxAppliedl = 0;
	
	var relevantZips = getRelevantZipCodes();
	
	//update local bounds
	for(var key in relevantZips){
		var satAvg = relevantZips[key].getAvgSat();
		if(satAvg > maxSatl) maxSatl = satAvg;
		if(satAvg < minSatl) minSatl = satAvg;
		
		var gpaAvg = relevantZips[key].getAvgGpa();
		if(gpaAvg > maxGpal) maxGpal = gpaAvg;
		if(gpaAvg < minGpal) minGpal = gpaAvg;
		
		var applied = relevantZips[key].applied;
		if(applied > maxAppliedl) maxAppliedl = applied;
		if(applied < minAppliedl) minAppliedl = applied;
		
		var enrolled = relevantZips[key].enrolled;
		if(enrolled > maxEnrolledl) maxEnrolledl = enrolled;
		if(enrolled < minEnrolledl) minEnrolledl = enrolled;
	}
	
	for (var key in zipCodes) {
		//zipCodes[key].poly.fillColor = getFillShading(0, 0, 500);
		zipCodes[key].poly.setMap(null);
	}
	
	for (var key in relevantZips) {
		var min, max, val;
		if (currentMetric === "sat") {
			min = minSatl;
			max = maxSatl;
			val = relevantZips[key].getAvgSat();
		}else if (currentMetric === "gpa") {
			min = minGpal;
			max = maxGpal;
			val = relevantZips[key].getAvgGpa();
		}else if (currentMetric === "enrolled") {
			min = minEnrolledl;
			max = maxEnrolledl;
			val = relevantZips[key].enrolled;
		}else if (currentMetric === "applied"){
			min = minAppliedl;
			max = maxAppliedl;
			val = relevantZips[key].applied;
		}else{
			alert("Invalid recolor() metric: "+metric);
		}
		
		//Recolor the polygon based on selected metric
		relevantZips[key].poly.fillColor = getFillShading(val, min, max);
		relevantZips[key].poly.setMap(map);
		
		//Set min and max
		var minDiv = document.getElementById('keyMinDiv'),
			maxDiv = document.getElementById('keyMaxDiv');
		minDiv.innerHTML = "<h5>"+min.toFixed(2)+"</h5>";
		maxDiv.innerHTML = "<h5>"+max.toFixed(2)+"</h5>";
		
	}
	
}

/*
 * Get the zip codes relevant to the current situation.
 * Returns a subset of zipCodes.
 * If dynamic recoloring is enabled, return zip codes whose center is
 * 	within map bounds. Else return all zip codes.
 */
function getRelevantZipCodes(){
	var dynamicRecoloringBox = document.getElementById('dynamicRecoloringBox');
	if(!dynamicRecoloringBox.checked){
		return zipCodes;
	}else{
		var bounds = map.getBounds();
		var rtnval = [];
		
		for (var key in zipCodes) {
			if (bounds.contains(new google.maps.LatLng(zipCodes[key].center[1], zipCodes[key].center[0]))) {
				rtnval[key] = zipCodes[key];
			}
		}
		return rtnval;
	}
}

/**
 * Recolor the zip code polygons based on the metric selected -- non-dynamic
 * @param {Object} metric
 */
function recolor(metric){
	for (var key in zipCodes) {
		var min, max, val;
		if (currentMetric === "sat") {
			min = minSat;
			max = maxSat;
			val = zipCodes[key].getAvgSat();
		}
		else if (currentMetric === "gpa") {
			min = minGpa;
			max = maxGpa;
			val = zipCodes[key].getAvgGpa();
		}else if (currentMetric === "enrolled") {
			min = minEnrolled;
			max = maxEnrolled;
			val = zipCodes[key].enrolled;
		}else if (currentMetric === "applied"){
			min = minApplied;
			max = maxApplied;
			val = zipCodes[key].applied;
		}else{
			alert("Invalid recolor() metric: "+metric);
		}
		
		//Recolor the polygon based on selected metric
		zipCodes[key].poly.fillColor = getFillShading(val, min, max);
		zipCodes[key].poly.setMap(map);
		
		//Set min and max
		var minDiv = document.getElementById('keyMinDiv'),
			maxDiv = document.getElementById('keyMaxDiv');
		minDiv.innerHTML = "<h5>"+min.toFixed(2)+"</h5>";
		maxDiv.innerHTML = "<h5>"+max.toFixed(2)+"</h5>";
	}	
} 

/**
 * Get fill shading given value, min and max
 * 
 * @param {Object} val
 * @param {Object} min
 * @param {Object} max
 */
function getFillShading(val, min, max){
	var pct;
	if(max != min){
		pct = 100.0 * (val - min) / (max - min); 
	}else{
		//If this is the only zip code in existence, set to 50%
		pct = 50.0
	}
	
	if(pct<0 || pct>100.5 || isNaN(pct)) alert("Invalid zip shading percentage: "+pct+", "+val+", "+min+", "+max);
	if(DARK_HIGH) pct = 100 - pct;
	pct *= (100 - 2*MIN_COLOR_PCT)/100;
	pct += MIN_COLOR_PCT;
	return "hsl(271, 76%, "+pct+"%)";

}
